home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume20 / rc / part02 < prev    next >
Encoding:
Text File  |  1991-05-22  |  50.8 KB  |  2,361 lines

  1. Newsgroups: comp.sources.misc
  2. From: Byron Rakitzis <byron@archone.tamu.edu>
  3. Subject:  v20i011:  rc - A Plan 9 shell reimplementation, Part02/04
  4. Message-ID: <1991May22.154211.3120@sparky.IMD.Sterling.COM>
  5. Date: Wed, 22 May 1991 15:42:11 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Md4-Signature: 2aa5c82d1e3b0476a2c6d8697913125c
  8.  
  9. Submitted-by: Byron Rakitzis <byron@archone.tamu.edu>
  10. Posting-number: Volume 20, Issue 11
  11. Archive-name: rc/part02
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then feed it
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # Contents:  fn.c footobar.c glom.c input.c lex.c walk.c
  20. # Wrapped by kent@sparky on Wed May 22 01:21:49 1991
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 2 (of 4)."'
  24. if test -f 'fn.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'fn.c'\"
  26. else
  27.   echo shar: Extracting \"'fn.c'\" \(4435 characters\)
  28.   sed "s/^X//" >'fn.c' <<'END_OF_FILE'
  29. X/*
  30. X   fn.c: functions for adding and deleting functions from the symbol table.
  31. X   Support for signal handlers is also found here.
  32. X*/
  33. X
  34. X#include <signal.h>
  35. X#include "rc.h"
  36. X#include "utils.h"
  37. X#include "status.h"
  38. X#include "tree.h"
  39. X#include "hash.h"
  40. X#include "footobar.h"
  41. X#include "walk.h"
  42. X#include "nalloc.h"
  43. X#include "sigmsgs.h"
  44. X#include "builtins.h"
  45. X#include "input.h"
  46. X
  47. Xstatic void fn_handler(int);
  48. X
  49. Xstatic Node *handlers[NUMOFSIGNALS], null_function;
  50. Xstatic boolean runexit = FALSE;
  51. X
  52. X/* set signals to default values for rc. this means that interactive shells ignore SIGQUIT, etc. */
  53. X
  54. Xvoid inithandler() {
  55. X    if (interactive) {
  56. X        signal(SIGINT, sig);
  57. X        handlers[SIGINT] = &null_function;
  58. X        if (!dashdee) {
  59. X            signal(SIGQUIT, SIG_IGN);
  60. X            handlers[SIGQUIT] = &null_function;
  61. X        }
  62. X    }
  63. X    null_function.type = BODY;
  64. X    null_function.u[0].p = null_function.u[1].p = NULL;
  65. X}
  66. X
  67. X/* only run this in a child process! resets signals to their default values */
  68. X
  69. Xvoid setsigdefaults(void) {
  70. X    int i;
  71. X
  72. X    /*
  73. X       General housekeeping: (setsigdefaults happens after fork(), so it's a convenient
  74. X       place to clean up)
  75. X    */
  76. X
  77. X    interactive = FALSE;
  78. X    if (histstr != NULL)    /* Close an open history file */
  79. X        close(histfd);
  80. X
  81. X    /* Restore signals to SIG_DFL */
  82. X
  83. X    for (i = 1; i < NUMOFSIGNALS; i++) { /* signal 0 is never used (bogus) */
  84. X        if (handlers[i] != NULL) {
  85. X            handlers[i] = NULL;
  86. X            signal(i, SIG_DFL);
  87. X        }
  88. X    }
  89. X    runexit = FALSE; /* No sigexit on subshells */
  90. X}
  91. X
  92. X/* rc's exit. if runexit is set, run the sigexit function. */
  93. X
  94. Xvoid rc_exit(int stat) {
  95. X    static char *sigexit[2] = { "sigexit", NULL };
  96. X
  97. X    if (runexit) {
  98. X        runexit = FALSE;
  99. X        funcall(sigexit);
  100. X        exit(getstatus());
  101. X    } else {
  102. X        exit(stat);
  103. X    }
  104. X}
  105. X
  106. X/* the signal handler for all functions. calls walk() */
  107. X
  108. Xstatic void fn_handler(int s) {
  109. X    if (s < 0 || s >= NUMOFSIGNALS)
  110. X        rc_error("unknown signal!?");
  111. X
  112. X    signal(s, fn_handler); /* sgi seems to require re-signalling */
  113. X    walk(handlers[s], TRUE);
  114. X}
  115. X
  116. X/*
  117. X   assign a function in Node form. Check to see if the function is also a signal, and set the
  118. X   signal vectors appropriately.
  119. X*/
  120. X
  121. Xvoid fnassign(char *name, Node *def) {
  122. X    Node *newdef = treecpy(def == NULL ? &null_function : def, ealloc); /* important to do the treecopy first */
  123. X    Function *new = get_fn_place(name);
  124. X    int i;
  125. X
  126. X    new->def = newdef;
  127. X    new->extdef = NULL;
  128. X
  129. X    if (strncmp(name, "sig", sizeof "sig" - 3) == 0) { /* slight optimization */
  130. X        if (streq(name, "sigexit"))
  131. X            runexit = TRUE;
  132. X        for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
  133. X            if (streq(signals[i][0], name)) {
  134. X                if (newdef != NULL) {
  135. X                    handlers[i] = newdef;
  136. X                    signal(i, fn_handler);
  137. X                } else {
  138. X                    handlers[i] = &null_function;
  139. X                    signal(i, SIG_IGN);
  140. X                }
  141. X                break;
  142. X            }
  143. X    }
  144. X}
  145. X
  146. X/* assign a function from the environment. store just the external representation */
  147. X
  148. Xvoid fnassign_string(char *extdef) {
  149. X    char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
  150. X    Function *new;
  151. X
  152. X    if (name == NULL)
  153. X        return;
  154. X
  155. X    new = get_fn_place(name);
  156. X    new->def = NULL;
  157. X    new->extdef = ecpy(extdef);
  158. X}
  159. X
  160. X/* return a function in Node form, evaluating an entry from the environment if necessary */
  161. X
  162. XNode *fnlookup(char *name) {
  163. X    Function *look = lookup_fn(name);
  164. X    Node *ret;
  165. X
  166. X    if (look == NULL)
  167. X        return NULL; /* not found */
  168. X    if (look->def != NULL)
  169. X        return look->def;
  170. X    if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
  171. X        return &null_function;
  172. X
  173. X    ret = parse_fn(name, look->extdef);
  174. X
  175. X    if (ret == NULL) {
  176. X        efree(look->extdef);
  177. X        look->extdef = NULL;
  178. X        return &null_function;
  179. X    } else {
  180. X        return look->def = treecpy(ret, ealloc); /* Need to take it out of talloc space */
  181. X    }
  182. X}
  183. X
  184. X/* return a function in string form (used by makeenv) */
  185. X
  186. Xchar *fnlookup_string(char *name) {
  187. X    Function *look = lookup_fn(name);
  188. X
  189. X    if (look == NULL)
  190. X        return NULL;
  191. X    if (look->extdef != NULL)
  192. X        return look->extdef;
  193. X    return look->extdef = fun2str(name, look->def);
  194. X}
  195. X
  196. X/*
  197. X   remove a function from the symbol table. If it also defines a signal handler, restore the signal handler
  198. X   to its default value.
  199. X*/
  200. X
  201. Xvoid fnrm(char *name) {
  202. X    int i;
  203. X
  204. X    for (i = 1; i < NUMOFSIGNALS; i++) /* signal 0 unused */
  205. X        if (streq(signals[i][0], name)) {
  206. X            handlers[i] = NULL;
  207. X            if (i == SIGINT)
  208. X                signal(i, sig); /* restore default signal handler for rc */
  209. X            else if (i == SIGQUIT && !dashdee)
  210. X                signal(i, SIG_IGN);     /* ditto */
  211. X            else
  212. X                signal(i, SIG_DFL);
  213. X        }
  214. X
  215. X    if (streq(name, "sigexit"))
  216. X        runexit = FALSE;
  217. X
  218. X    delete_fn(name);
  219. X}
  220. END_OF_FILE
  221.   if test 4435 -ne `wc -c <'fn.c'`; then
  222.     echo shar: \"'fn.c'\" unpacked with wrong size!
  223.   fi
  224.   # end of 'fn.c'
  225. fi
  226. if test -f 'footobar.c' -a "${1}" != "-c" ; then 
  227.   echo shar: Will not clobber existing file \"'footobar.c'\"
  228. else
  229.   echo shar: Extracting \"'footobar.c'\" \(7836 characters\)
  230.   sed "s/^X//" >'footobar.c' <<'END_OF_FILE'
  231. X/*
  232. X   footobar.c: a collection of functions to convert internal representations of
  233. X   variables and functions to external representations, and vice versa
  234. X*/
  235. X
  236. X#include "rc.h"
  237. X#include "utils.h"
  238. X#include "lex.h"
  239. X#include "footobar.h"
  240. X#include "nalloc.h"
  241. X#include "input.h"
  242. X#include "list.h"
  243. X
  244. X#define FSCHAR '\1'
  245. X#define FSSTRING "\1"
  246. X
  247. Xstatic char *getenvw(char *, boolean);
  248. Xstatic void funcat(char *);
  249. Xstatic void strtree(Node *);
  250. X
  251. Xstatic char *fun;
  252. Xstatic SIZE_T funsize, funpos;
  253. X
  254. X/* a specialized strcat, used in strtree */
  255. X
  256. Xstatic void funcat(char *s) {
  257. X    SIZE_T l = strlen(s);
  258. X    char *new;
  259. X
  260. X    if (l + funpos > funsize) {
  261. X        new = nalloc(funsize *= 2);
  262. X        memcpy(new, fun, funpos);
  263. X        new[funpos] = 0;
  264. X        fun = new;
  265. X    }
  266. X    strcpy(fun + funpos, s);
  267. X    funpos += l;
  268. X}
  269. X
  270. X/* used to turn a function in Node * form into something we can export to the environment */
  271. X
  272. Xchar *fun2str(char *name, Node *s) {
  273. X    fun = nalloc(funsize = 512);
  274. X    funpos = 0;
  275. X    funcat("fn_");
  276. X    funcat(name);
  277. X    funcat("={");
  278. X    strtree(s);
  279. X    funcat("}");
  280. X    return ecpy(fun); /* put into malloc space */
  281. X}
  282. X
  283. X/* ptree is used by whatis in order to print the definition of a function to the terminal */
  284. X
  285. Xchar *ptree(Node *s) {
  286. X    fun = nalloc(funsize = 512);
  287. X    funpos = 0;
  288. X    fun[0] = 0;
  289. X    strtree(s);
  290. X    return fun;
  291. X}
  292. X
  293. X/* save some code space by gathering this operation in a function */
  294. X
  295. Xstatic void catredir(int i) {
  296. X    switch (i) {
  297. X    case CREATE: funcat(">"); break;
  298. X    case APPEND: funcat(">>"); break;
  299. X    case HEREDOC: funcat("<<"); break;
  300. X    case HERESTRING: funcat("<<<"); break;
  301. X    case FROM: funcat("<"); break;
  302. X    }
  303. X}
  304. X
  305. X/* convert a function in Node * form into something rc can parse (and humans can read?) */
  306. X
  307. Xstatic void strtree(Node *n) {
  308. X    int defaultfd;
  309. X    char b[16];
  310. X
  311. X    if (n == NULL) {
  312. X        funcat("()");
  313. X        return;
  314. X    }
  315. X
  316. X    switch (n->type) {
  317. X    case rDUP:
  318. X        catredir(n->u[0].i);
  319. X        if (n->u[2].i != -1)
  320. X            sprint(b, "[%d=%d]", n->u[1].i, n->u[2].i);
  321. X        else
  322. X            sprint(b, "[%d=]", n->u[1].i);
  323. X        funcat(b);
  324. X        break;
  325. X    case rWORD:
  326. X        if (*n->u[0].s == '\'')
  327. X            funcat(strprint(n->u[0].s + 1, TRUE, FALSE));
  328. X        else
  329. X            funcat(strprint(n->u[0].s, FALSE, FALSE));
  330. X        break;
  331. X    case BACKQ:
  332. X        if (n->u[0].p != NULL && n->u[0].p->type == VAR
  333. X            && n->u[0].p->u[0].p != NULL && n->u[0].p->u[0].p->type == rWORD
  334. X            && streq(n->u[0].p->u[0].p->u[0].s,"ifs")) {
  335. X            funcat("`{");
  336. X        } else {
  337. X            funcat("``");
  338. X            strtree(n->u[0].p);
  339. X            funcat("{");
  340. X        }
  341. X        strtree(n->u[1].p);
  342. X        funcat("}");
  343. X        break;
  344. X    case rBANG:
  345. X        funcat("! ");
  346. X        strtree(n->u[0].p);
  347. X        break;
  348. X    case NOWAIT:
  349. X        strtree(n->u[0].p);
  350. X        funcat("&");
  351. X        break;
  352. X    case rCOUNT:
  353. X        funcat("$#");
  354. X        strtree(n->u[0].p);
  355. X        break;
  356. X    case rFLAT:
  357. X        funcat("$^");
  358. X        strtree(n->u[0].p);
  359. X        break;
  360. X    case RMFN:
  361. X        funcat("fn ");
  362. X        strtree(n->u[0].p);
  363. X        break;
  364. X    case rSUBSHELL:
  365. X        funcat("@ ");
  366. X        strtree(n->u[0].p);
  367. X        break;
  368. X    case VAR:
  369. X        funcat("$");
  370. X        strtree(n->u[0].p);
  371. X        break;
  372. X    case rANDAND:
  373. X        strtree(n->u[0].p);
  374. X        funcat("&&");
  375. X        strtree(n->u[1].p);
  376. X        break;
  377. X    case ASSIGN:
  378. X        strtree(n->u[0].p);
  379. X        funcat("=");
  380. X        strtree(n->u[1].p);
  381. X        break;
  382. X    case BODY:
  383. X        if (n->u[1].p != NULL)
  384. X            funcat("{");
  385. X        strtree(n->u[0].p);
  386. X        if (n->u[1].p != NULL) {
  387. X            funcat(";");
  388. X            strtree(n->u[1].p);
  389. X            funcat("}");
  390. X        }
  391. X        break;
  392. X    case BRACE:
  393. X        funcat("{");
  394. X        strtree(n->u[0].p);
  395. X        funcat("}");
  396. X        strtree(n->u[1].p);
  397. X        break;
  398. X    case CONCAT:
  399. X        strtree(n->u[0].p);
  400. X        funcat("^");
  401. X        strtree(n->u[1].p);
  402. X        break;
  403. X    case rELSE:
  404. X        funcat("{");
  405. X        strtree(n->u[0].p);
  406. X        funcat("}else ");
  407. X        strtree(n->u[1].p);
  408. X        break;
  409. X    case EPILOG:
  410. X    case PRE:
  411. X        strtree(n->u[0].p);
  412. X        funcat(" ");
  413. X        strtree(n->u[1].p);
  414. X        break;
  415. X    case NEWFN:
  416. X        funcat("fn ");
  417. X        strtree(n->u[0].p);
  418. X        funcat(" {");
  419. X        strtree(n->u[1].p);
  420. X        funcat("}");
  421. X        break;
  422. X    case rIF:
  423. X        funcat("if(");
  424. X        strtree(n->u[0].p);
  425. X        funcat(")");
  426. X        strtree(n->u[1].p);
  427. X        break;
  428. X    case rOROR:
  429. X        strtree(n->u[0].p);
  430. X        funcat("||");
  431. X        strtree(n->u[1].p);
  432. X        break;
  433. X    case ARGS:
  434. X        strtree(n->u[0].p);
  435. X        funcat(" ");
  436. X        strtree(n->u[1].p);
  437. X        break;
  438. X    case rSWITCH:
  439. X        funcat("switch(");
  440. X        strtree(n->u[0].p);
  441. X        funcat(")");
  442. X        strtree(n->u[1].p);
  443. X        break;
  444. X    case MATCH:
  445. X        funcat("~ ");
  446. X        strtree(n->u[0].p);
  447. X        funcat(" ");
  448. X        strtree(n->u[1].p);
  449. X        break;
  450. X    case VARSUB:
  451. X        funcat("$");
  452. X        strtree(n->u[0].p);
  453. X        funcat("(");
  454. X        strtree(n->u[1].p);
  455. X        funcat(")");
  456. X        break;
  457. X    case rWHILE:
  458. X        funcat("while(");
  459. X        strtree(n->u[0].p);
  460. X        funcat(")");
  461. X        strtree(n->u[1].p);
  462. X        break;
  463. X    case LAPPEND:
  464. X        funcat("(");
  465. X        strtree(n->u[0].p);
  466. X        funcat(" ");
  467. X        strtree(n->u[1].p);
  468. X        funcat(")");
  469. X        break;
  470. X    case FORIN:
  471. X        funcat("for(");
  472. X        strtree(n->u[0].p);
  473. X        funcat(" in ");
  474. X        strtree(n->u[1].p);
  475. X        funcat(")");
  476. X        strtree(n->u[2].p);
  477. X        break;
  478. X    case rPIPE:
  479. X        funcat("{");
  480. X        strtree(n->u[2].p);
  481. X        if (n->u[0].i == 1) {
  482. X            if (n->u[1].i == 0)
  483. X                sprint(b, "}|{");
  484. X            else
  485. X                sprint(b, "}|[1=%d]{", n->u[1].p);
  486. X        } else {
  487. X            if (n->u[1].i == 0)
  488. X                sprint(b, "}|[%d]{", n->u[0].p);
  489. X            else
  490. X                sprint(b, "}|[%d=%d]{", n->u[0].i, n->u[1].i);
  491. X        }
  492. X        funcat(b);
  493. X        strtree(n->u[3].p);
  494. X        funcat("}");
  495. X        break;
  496. X    case NMPIPE:
  497. X        catredir(n->u[0].i);
  498. X        if (n->u[1].i != 1) {
  499. X            sprint(b, "[%d]{", n->u[1].i);
  500. X            funcat(b);
  501. X        } else
  502. X            funcat("{");
  503. X        strtree(n->u[2].p);
  504. X        funcat("}");
  505. X        break;
  506. X    case rREDIR:
  507. X        defaultfd = (n->u[0].i == CREATE || n->u[0].i == APPEND);
  508. X        catredir(n->u[0].i);
  509. X        if (n->u[1].i != defaultfd) {
  510. X            sprint(b, "[%d]", n->u[1].i);
  511. X            funcat(b);
  512. X        }
  513. X        strtree(n->u[2].p);
  514. X        break;
  515. X     }
  516. X}
  517. X
  518. X/* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
  519. X
  520. Xchar *list2str(char *name, List *s) {
  521. X    SIZE_T size;
  522. X    List *t;
  523. X    char *w;
  524. X
  525. X    size = listlen(s);
  526. X    size += strlen(name);
  527. X
  528. X    w = ealloc(size + 2);
  529. X    t = s;
  530. X    strcpy(w, name);
  531. X    strcat(w, "=");
  532. X    strcat(w, t->w);
  533. X    for (s = s->n; s != NULL; s = s->n) {
  534. X        strcat(w, FSSTRING);
  535. X        strcat(w, s->w);
  536. X    }
  537. X    return w;
  538. X}
  539. X
  540. X/* convert a List to an array, for execve() */
  541. X
  542. Xchar **list2array(List *s, boolean print) {
  543. X    char **av;
  544. X    int i;
  545. X
  546. X    av = nalloc((listnel(s) + 1) * sizeof (char *));
  547. X
  548. X    for (i = 0; s != NULL; i++) {
  549. X        av[i] = s->w;
  550. X        if (print)
  551. X            fprint(2,"%s",s->w);
  552. X        s = s->n;
  553. X        if (print) {
  554. X            if (s == NULL)
  555. X                fprint(2,"\n");
  556. X            else
  557. X                fprint(2," ");
  558. X        }
  559. X    }
  560. X    av[i] = NULL;
  561. X    return av;
  562. X}
  563. X
  564. X/* figure out the name of a variable given an environment string. copy this into malloc space */
  565. X
  566. Xchar *get_name(char *s) {
  567. X    char *r;
  568. X    SIZE_T i;
  569. X
  570. X    for (i = 0; s[i] != '\0' && s[i] != '='; i++)
  571. X        ;
  572. X
  573. X    if (s[i] == '\0')
  574. X        return NULL;
  575. X
  576. X    r = ealloc(i + 1);
  577. X
  578. X    r[i] = '\0';
  579. X
  580. X    while (i > 0) {
  581. X        --i;
  582. X        r[i] = s[i];
  583. X    }
  584. X    return r;
  585. X}
  586. X
  587. X/* get the next word from a variable's value as represented in the environment. */
  588. X
  589. Xstatic char *getenvw(char *s, boolean saw_alpha) {
  590. X    char *r;
  591. X    SIZE_T i,j;
  592. X
  593. X    for (i = j = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
  594. X        ;
  595. X
  596. X    if (i == 0)
  597. X        if(s[i] == '\0' && !saw_alpha)
  598. X            return NULL;
  599. X        else {
  600. X            r = enew(char);
  601. X            *r = '\0';
  602. X            return r;
  603. X        }
  604. X
  605. X    r = ealloc(i + j + 1);
  606. X
  607. X    r[i + j] = '\0';
  608. X
  609. X    while (i > 0) {
  610. X        --i;
  611. X        r[i + j] = s[i];
  612. X    }
  613. X    return r;
  614. X}
  615. X
  616. X/* take an environment entry for a variable (elements ^A separated) and turn it into a List */
  617. X
  618. XList *parse_var(char *name, char *extdef) {
  619. X    List *r, *top = r;
  620. X    char *f;
  621. X    boolean saw_alpha;
  622. X
  623. X    top = r = enew(List);
  624. X    extdef += strlen(name) + 1;
  625. X
  626. X    
  627. X    if ((f = getenvw(extdef, FALSE)) == NULL)
  628. X        return NULL;
  629. X
  630. X    while (1) {
  631. X        r->w = f;
  632. X        r->m = NULL;
  633. X        extdef += strlen(f);
  634. X        if (*extdef == FSCHAR) {
  635. X            extdef++;
  636. X            saw_alpha = TRUE;
  637. X        } else {
  638. X            saw_alpha = FALSE;
  639. X        }        
  640. X        if ((f = getenvw(extdef, saw_alpha)) == NULL) {
  641. X            r->n = NULL;
  642. X            break;
  643. X        }
  644. X        r = r->n = enew(List);
  645. X    }
  646. X    return top;
  647. X}
  648. X
  649. X/* get an environment entry for a function and have rc parse it. */
  650. X
  651. XNode *parse_fn(char *name, char *extdef) {
  652. X    Node *def;
  653. X    int len;
  654. X
  655. X    len = strlen(name);
  656. X    extdef[2] = ' ';
  657. X    extdef[3 + len] = ' ';
  658. X    def = parseline(extdef);
  659. X    extdef[2] = '_';
  660. X    extdef[3 + len] = '=';
  661. X
  662. X    if (def == NULL || def->type != NEWFN)
  663. X        return NULL;
  664. X    else
  665. X        return def->u[1].p;
  666. X}
  667. END_OF_FILE
  668.   if test 7836 -ne `wc -c <'footobar.c'`; then
  669.     echo shar: \"'footobar.c'\" unpacked with wrong size!
  670.   fi
  671.   # end of 'footobar.c'
  672. fi
  673. if test -f 'glom.c' -a "${1}" != "-c" ; then 
  674.   echo shar: Will not clobber existing file \"'glom.c'\"
  675. else
  676.   echo shar: Extracting \"'glom.c'\" \(8367 characters\)
  677.   sed "s/^X//" >'glom.c' <<'END_OF_FILE'
  678. X/* glom.c: builds an argument list out of words, variables, etc. */
  679. X
  680. X#ifndef NONMPIPES
  681. X#include <sys/types.h>
  682. X#include <sys/stat.h>
  683. X#endif
  684. X#include "rc.h"
  685. X#include "utils.h"
  686. X#include "nalloc.h"
  687. X#include "glom.h"
  688. X#include "hash.h"
  689. X#include "walk.h"
  690. X#include "status.h"
  691. X#include "exec.h"
  692. X#include "lex.h"
  693. X#include "open.h"
  694. X#include "list.h"
  695. X
  696. Xstatic List *backq(Node *, Node *);
  697. Xstatic List *bqinput(List *, int);
  698. Xstatic List *count(List *);
  699. Xstatic List *mknmpipe(Node *);
  700. X
  701. XRq *redirq = NULL;
  702. XList *fifoq = NULL;
  703. X
  704. XList *word(char *w, char *m) {
  705. X    List *s;
  706. X
  707. X    if (w == NULL)
  708. X        return NULL;
  709. X    if (*w == '\'') {
  710. X        m = NULL; /* m is null, or had better be! */
  711. X        w++;
  712. X    }
  713. X
  714. X    s = nnew(List);
  715. X    s->w = w;
  716. X    s->m = m;
  717. X    s->n = NULL;
  718. X    return s;
  719. X}
  720. X
  721. X/*
  722. X   Append list s2 to list s1 by copying s1 and making the new copy
  723. X   point at s2.
  724. X*/
  725. X
  726. XList *append(List *s1, List *s2) {
  727. X    List *r, *top;
  728. X
  729. X    if (s1 == NULL)
  730. X        return s2;
  731. X    if (s2 == NULL)
  732. X        return s1;
  733. X
  734. X    r = top = nnew(List);
  735. X    while (1) {
  736. X        r->w = s1->w;
  737. X        r->m = s1->m;
  738. X        if ((s1 = s1->n) == NULL)
  739. X            break;
  740. X        r = r->n = nnew(List);
  741. X    }
  742. X
  743. X    r->n = s2;
  744. X
  745. X    return top;
  746. X}
  747. X
  748. XList *concat(List *s1, List *s2) {
  749. X    int n1, n2;
  750. X    SIZE_T y,z;
  751. X    List *n, *s;
  752. X
  753. X    if (s1 == NULL)
  754. X        return s2;
  755. X    if (s2 == NULL)
  756. X        return s1;
  757. X
  758. X    n1 = listnel(s1);
  759. X    n2 = listnel(s2);
  760. X
  761. X    if (n1 != n2 && n1 != 1 && n2 != 1)
  762. X        rc_error("bad concatenation");
  763. X
  764. X    n = s = nnew(List);
  765. X
  766. X    while (1) {
  767. X        z = strlen(s1->w) + strlen(s2->w) + 1;
  768. X        n->w = nalloc(z);
  769. X        strcpy(n->w,s1->w);
  770. X        strcat(n->w,s2->w);
  771. X        if (s1->m == NULL && s2->m == NULL) {
  772. X            n->m = NULL;
  773. X        } else {
  774. X            n->m = nalloc(z);
  775. X            y = strlen(s1->w);
  776. X            if (s1->m == NULL)
  777. X                clear(n->m, y);
  778. X            else
  779. X                memcpy(n->m, s1->m, y);
  780. X            if (s2->m == NULL)
  781. X                clear(n->m + y, strlen(s2->w));
  782. X            else
  783. X                memcpy(n->m + y, s2->m, strlen(s2->w));
  784. X            n->m[z] = 0;
  785. X        }
  786. X        if (n1 > 1)
  787. X            s1 = s1->n;
  788. X        if (n2 > 1)
  789. X            s2 = s2->n;
  790. X        if (s1 == NULL || s2 == NULL || (n1 == 1  && n2 == 1)) {
  791. X            n->n = NULL;
  792. X            return s;
  793. X        }
  794. X        n->n = nnew(List);
  795. X        n = n->n;
  796. X    }
  797. X}
  798. X
  799. XList *varsub(List *v, List *subs) {
  800. X    int i,j;
  801. X    int n;
  802. X    List *r,*s;
  803. X    List *top,*cat;
  804. X
  805. X    n = listnel(v);
  806. X
  807. X    top = cat = NULL;
  808. X
  809. X    for (s = subs; s != NULL; s = s->n) {
  810. X        i = a2u(s->w);
  811. X        if (i < 1)
  812. X            rc_error("bad subscript");
  813. X        if (i <= n) {
  814. X            for (j = 1, r = v; j != i; j++, r = r->n)
  815. X                ; /* loop until r == v(i) */
  816. X            if (top == NULL) {
  817. X                top = cat = nnew(List);
  818. X            } else {
  819. X                cat->n = nnew(List);
  820. X                cat = cat->n;
  821. X            }
  822. X            cat->w = r->w;
  823. X            cat->m = r->m;
  824. X        }
  825. X    }
  826. X
  827. X    if (top == NULL)
  828. X        return NULL;
  829. X
  830. X    cat->n = NULL;
  831. X    return top;
  832. X}
  833. X
  834. XList *flatten(List *s) {
  835. X    List *r;
  836. X
  837. X    if (s == NULL || s->n == NULL)
  838. X        return s;
  839. X
  840. X    r = nnew(List);
  841. X    r->w = nalloc(listlen(s) + 1);
  842. X    r->m = NULL; /* flattened lists come from variables, so no meta */
  843. X    r->n = NULL;
  844. X
  845. X    strcpy(r->w, s->w);
  846. X
  847. X    do {
  848. X        s = s->n;
  849. X        strcat(r->w, " ");
  850. X        strcat(r->w, s->w);
  851. X    } while (s->n != NULL);
  852. X
  853. X    return r;
  854. X}
  855. X
  856. Xstatic List *count(List *l) {
  857. X    List *s = nnew(List);
  858. X    char buf[16];
  859. X
  860. X    s->w = ncpy(sprint(buf, "%d", listnel(l)));
  861. X    s->n = NULL;
  862. X    s->m = NULL;
  863. X    return s;
  864. X}
  865. X
  866. Xvoid assign(List *s1, List *s2, boolean stack) {
  867. X    List *val = s2;
  868. X
  869. X    if (s1 == NULL)
  870. X        rc_error("null variable name");
  871. X    if (s1->n != NULL)
  872. X        rc_error("multi-word variable name");
  873. X    if (*s1->w == '\0')
  874. X        rc_error("zero-length variable name");
  875. X    if (a2u(s1->w) != -1)
  876. X        rc_error("numeric variable name");
  877. X    if (s1->w[0] == '*' && s1->w[1] == '\0')
  878. X        val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
  879. X
  880. X    if (s2 != NULL || stack) {
  881. X        varassign(s1->w, val, stack);
  882. X        alias(s1->w, val, stack);
  883. X    } else
  884. X        varrm(s1->w, stack);
  885. X}
  886. X
  887. X/*
  888. X   The following two functions are by the courtesy of Paul Haahr,
  889. X   who could not stand the incompetence of my own backquote implementation.
  890. X*/
  891. X
  892. X#define BUFSIZE    ((SIZE_T) 1000)
  893. X
  894. Xstatic List *bqinput(List *list, int fd) {
  895. X    char *s, *bufend;
  896. X    List *lp, *prev;
  897. X    SIZE_T nremain, bufsize;
  898. X    static char isifs[256];
  899. X
  900. X    clear(isifs, sizeof isifs);
  901. X    isifs['\0'] = 1;
  902. X    for (lp = list; list != NULL; list = list->n)
  903. X        for (s = list->w; *s != '\0'; s++)
  904. X            isifs[*(unsigned char *)s] = 1;
  905. X
  906. X    nremain = bufsize = BUFSIZE;
  907. X    lp = list = nnew(List);
  908. X    s  = list->w = nalloc(bufsize + 1);
  909. X    list->m = NULL;
  910. X    prev = NULL;
  911. X    while (1) {
  912. X        int n;
  913. X
  914. X        if (nremain == 0) {
  915. X            SIZE_T m = s - lp->w;
  916. X            char *buf;
  917. X
  918. X            while (bufsize < m + BUFSIZE)
  919. X                bufsize *= 2;
  920. X            buf = nalloc(bufsize + 1);
  921. X            memcpy(buf, lp->w, m);
  922. X            lp->w = buf;
  923. X            lp->m = NULL;
  924. X            s = &buf[m];
  925. X            nremain = bufsize - m;
  926. X        }
  927. X        n = read(fd, s, nremain);
  928. X        if (n <= 0) {
  929. X            if (n == -1) {
  930. X                uerror("backquote read");
  931. X                rc_error(NULL);
  932. X            }
  933. X    /* break */    break;
  934. X        }
  935. X        nremain -= n;
  936. X        for (bufend = &s[n]; s < bufend; s++)
  937. X            if (isifs[*(unsigned char *)s]) {
  938. X                *s = '\0';
  939. X                prev = lp;
  940. X                lp = nnew(List);
  941. X                lp->w = s + 1;
  942. X                lp->m = NULL;
  943. X                prev->n = lp;
  944. X            }
  945. X    }
  946. X
  947. X    if (s == lp->w) {
  948. X        if (prev == NULL)
  949. X            list = NULL;
  950. X        else
  951. X            prev->n = NULL;
  952. X    } else {
  953. X        lp->n = NULL;
  954. X        *s = '\0';
  955. X    }
  956. X
  957. X    return list;
  958. X}
  959. X
  960. Xstatic List *backq(Node *ifsnode, Node *n) {
  961. X    int p[2], pid, sp;
  962. X    List *result, *ifs;
  963. X
  964. X    if (n == NULL)
  965. X        return NULL;
  966. X
  967. X    if (pipe(p) < 0) {
  968. X        uerror("pipe");
  969. X        rc_error(NULL);
  970. X    }
  971. X
  972. X    switch (pid = fork()) {
  973. X    case -1:
  974. X        uerror("fork");
  975. X        rc_error(NULL);
  976. X        /* NOTREACHED */
  977. X    case 0:
  978. X        setsigdefaults();
  979. X        dup2(p[1],1);
  980. X        close(p[0]);
  981. X        close(p[1]);
  982. X        redirq = NULL;
  983. X        fifoq = NULL;
  984. X        walk(n, FALSE);
  985. X        exit(getstatus());
  986. X        /* NOTREACHED */
  987. X    default:
  988. X        ifs = glom(ifsnode);
  989. X        close(p[1]);
  990. X        result = bqinput(ifs, p[0]);
  991. X        close(p[0]);
  992. X        while (pid != wait(&sp))
  993. X            ;
  994. X        statprint(sp);
  995. X        return result;
  996. X    }
  997. X}
  998. X
  999. Xvoid qredir(Node *n) {
  1000. X    Rq *next;
  1001. X
  1002. X    if (redirq == NULL) {
  1003. X        next = redirq = nnew(Rq);
  1004. X    } else {
  1005. X        for (next = redirq; next->n != NULL; next = next->n)
  1006. X            ;
  1007. X        next->n = nnew(Rq);
  1008. X        next = next->n;
  1009. X    }
  1010. X
  1011. X    next->r = n;
  1012. X    next->n = NULL;
  1013. X}
  1014. X
  1015. Xstatic List *mknmpipe(Node *n) {
  1016. X#ifdef NONMPIPES
  1017. X    rc_error("named pipes are not supported");
  1018. X    return NULL;
  1019. X#else
  1020. X    int fd;
  1021. X    char *fifoname, buf[32];
  1022. X    List *fifolist = nnew(List);
  1023. X    List *f = nnew(List);
  1024. X    static int fifonumber = 0;
  1025. X
  1026. X    fifoname = ncpy(sprint(buf,"/tmp/rc%d.%d", getpid(), fifonumber++));
  1027. X
  1028. X    if (mknod(fifoname, S_IFIFO | 0644, 0) < 0) {
  1029. X        uerror("mknod");
  1030. X        return NULL;
  1031. X    }
  1032. X
  1033. X    switch (fork()) {
  1034. X    case -1:
  1035. X        uerror("fork");
  1036. X        rc_error(NULL);
  1037. X        /* NOTREACHED */
  1038. X    case 0:
  1039. X        setsigdefaults();
  1040. X        fd = rc_open(fifoname, CREATE);
  1041. X        if (fd < 0) {
  1042. X            uerror("open");
  1043. X            exit(1);
  1044. X        }
  1045. X        if (dup2(fd, (n->u[0].i == FROM)) < 0) { /* stupid hack */
  1046. X            uerror("dup2");
  1047. X            exit(1);
  1048. X        }
  1049. X        close(fd);
  1050. X        redirq = NULL;
  1051. X        fifoq = NULL;
  1052. X        walk(n->u[2].p, FALSE);
  1053. X        exit(getstatus());
  1054. X        /* NOTREACHED */
  1055. X    default:
  1056. X        f->w = fifoname;
  1057. X        f->n = fifoq;
  1058. X        fifoq = f;
  1059. X
  1060. X        fifolist->w = fifoname;
  1061. X        fifolist->m = NULL;
  1062. X        fifolist->n = NULL;
  1063. X
  1064. X        return fifolist;
  1065. X    }
  1066. X#endif
  1067. X}
  1068. X
  1069. XList *glom(Node *n) {
  1070. X    Node *words;
  1071. X    List *v, *first, *last;
  1072. X    boolean dollarstar;
  1073. X
  1074. X    if (n == NULL)
  1075. X        return NULL;
  1076. X
  1077. X    switch (n->type) {
  1078. X    case ARGS:
  1079. X    case LAPPEND:
  1080. X        words = n->u[0].p;
  1081. X        last = NULL;
  1082. X        while (words != NULL && (words->type == ARGS || words->type == LAPPEND)) {
  1083. X            if (words->u[1].p != NULL && words->u[1].p->type != rWORD)
  1084. X                break;
  1085. X            first = glom(words->u[1].p);
  1086. X            if (first != NULL) {
  1087. X                first->n = last;
  1088. X                last = first;
  1089. X            }
  1090. X            words = words->u[0].p;
  1091. X        }
  1092. X        return append(append(glom(words), last), glom(n->u[1].p));
  1093. X    case BACKQ:
  1094. X        return backq(n->u[0].p,n->u[1].p);
  1095. X    case CONCAT:
  1096. X        first = glom(n->u[0].p); /* force left-to-right evaluation */
  1097. X        return concat(first, glom(n->u[1].p));
  1098. X    case rDUP:
  1099. X    case rREDIR:
  1100. X        qredir(n);
  1101. X        return NULL;
  1102. X    case rWORD:
  1103. X        return word(n->u[0].s,n->u[1].s);
  1104. X    case NMPIPE:
  1105. X        return mknmpipe(n);
  1106. X    default:
  1107. X        break;
  1108. X    }
  1109. X
  1110. X    /*
  1111. X           the next three operations depend on the left-child of glom
  1112. X       to be a variable name. Therefore they are all treated here.
  1113. X       (previously each function looked up and checked the validity
  1114. X       of a variable name)
  1115. X    */
  1116. X
  1117. X    v = glom(n->u[0].p);
  1118. X    if (v == NULL)
  1119. X        rc_error("null variable name");
  1120. X    if (v->n != NULL)
  1121. X        rc_error("multi-word variable name");
  1122. X    if (*v->w == '\0')
  1123. X        rc_error("zero-length variable name");
  1124. X
  1125. X    dollarstar = (v->w[0] == '*' && v->w[1] == '\0');
  1126. X    v = varlookup(v->w);
  1127. X    if (dollarstar)
  1128. X        v = v->n;
  1129. X
  1130. X    switch (n->type) {
  1131. X    default:
  1132. X        fprint(2,"glom: this can't happen\n");
  1133. X        exit(1);
  1134. X        /* NOTREACHED */
  1135. X    case rCOUNT:
  1136. X        return count(v);
  1137. X    case rFLAT:
  1138. X        return flatten(v);
  1139. X    case VAR:
  1140. X        return v;
  1141. X    case VARSUB:
  1142. X        return varsub(v, glom(n->u[1].p));
  1143. X    }
  1144. X
  1145. X}
  1146. END_OF_FILE
  1147.   if test 8367 -ne `wc -c <'glom.c'`; then
  1148.     echo shar: \"'glom.c'\" unpacked with wrong size!
  1149.   fi
  1150.   # end of 'glom.c'
  1151. fi
  1152. if test -f 'input.c' -a "${1}" != "-c" ; then 
  1153.   echo shar: Will not clobber existing file \"'input.c'\"
  1154. else
  1155.   echo shar: Extracting \"'input.c'\" \(6937 characters\)
  1156.   sed "s/^X//" >'input.c' <<'END_OF_FILE'
  1157. X/* input.c: i/o routines for files and pseudo-files (strings) */
  1158. X
  1159. X#include <errno.h>
  1160. X#include <setjmp.h>
  1161. X#include <stdarg.h>
  1162. X#include "rc.h"
  1163. X#include "input.h"
  1164. X#include "utils.h"
  1165. X#include "walk.h"
  1166. X#include "hash.h"
  1167. X#include "lex.h"
  1168. X#include "open.h"
  1169. X#include "nalloc.h"
  1170. X#include "except.h"
  1171. X#include "glom.h"
  1172. X#include "builtins.h"
  1173. X#include "parse.h"
  1174. X#include "tree.h"
  1175. X
  1176. X/*
  1177. X   warning, changes have been made to (fd|string)(gchar|ugchar) so that
  1178. X   you cannot unget EOF more than once. lex.c never does this, so I'm
  1179. X   safe, but if you unget EOF more than once, expect to be able to read
  1180. X   it back only once. The reason is that EOF is an int, whereas the buffers
  1181. X   are character buffers.
  1182. X*/
  1183. X
  1184. Xtypedef struct Input {
  1185. X    enum inputtype t;
  1186. X    char *ibuf;
  1187. X    int fd;
  1188. X    int index;
  1189. X    int read;
  1190. X    int lineno;
  1191. X} Input;
  1192. X
  1193. X#define BUFSIZE ((SIZE_T) 256)
  1194. X
  1195. X#ifdef READLINE
  1196. Xextern char *readline(char *);
  1197. Xextern void add_history(char *);
  1198. Xstatic char *rlinebuf;
  1199. X#endif
  1200. X
  1201. Xchar *prompt, *prompt2;
  1202. Xboolean rcrc;
  1203. Xchar *histstr;
  1204. Xint histfd;
  1205. X
  1206. Xstatic int dead(void);
  1207. Xstatic int fdgchar(void);
  1208. Xstatic int stringgchar(void);
  1209. Xstatic void history(void);
  1210. Xstatic void ugdead(int);
  1211. X
  1212. Xstatic char *inbuf;
  1213. Xstatic SIZE_T istacksize, chars_out, chars_in;
  1214. Xstatic boolean eofread = FALSE;
  1215. Xstatic Input *istack, *itop;
  1216. X
  1217. Xstatic int (*realgchar)(void);
  1218. Xstatic void (*realugchar)(int);
  1219. X
  1220. Xint last;
  1221. X
  1222. Xint gchar(void) {
  1223. X    if (eofread) {
  1224. X        eofread = FALSE;
  1225. X        return last = EOF;
  1226. X    }
  1227. X    return realgchar();
  1228. X}
  1229. X
  1230. Xvoid ugchar(int c) {
  1231. X    realugchar(c);
  1232. X}
  1233. X
  1234. Xstatic int dead() {
  1235. X    return last = EOF;
  1236. X}
  1237. X
  1238. Xstatic void ugdead(int c) {
  1239. X    return;
  1240. X}
  1241. X
  1242. Xstatic void ugalive(int c) {
  1243. X    if (c == EOF)
  1244. X        eofread = TRUE;
  1245. X    else
  1246. X        inbuf[--chars_out] = c;
  1247. X}
  1248. X
  1249. X/* get the next character from a string. */
  1250. X
  1251. Xstatic int stringgchar() {
  1252. X    return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]);
  1253. X}
  1254. X
  1255. X/*
  1256. X   read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor
  1257. X   the buffer to look like a regular fdgchar buffer.
  1258. X*/
  1259. X
  1260. Xstatic int fdgchar() {
  1261. X    if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */
  1262. X        do {
  1263. X#ifdef READLINE
  1264. X            if (interactive && istack->fd == 0) {
  1265. X                rlinebuf = readline(prompt);
  1266. X                if (rlinebuf == NULL) {
  1267. X                    chars_in = 0;
  1268. X                } else {
  1269. X                    if (*rlinebuf != '\0')
  1270. X                        add_history(rlinebuf);
  1271. X                    chars_in = strlen(rlinebuf) + 1;
  1272. X                    efree(inbuf);
  1273. X                    inbuf = ealloc(chars_in + 3);
  1274. X                    strcpy(inbuf+2, rlinebuf);
  1275. X                    strcat(inbuf+2, "\n");
  1276. X                    efree(rlinebuf);
  1277. X                }
  1278. X            } else
  1279. X#endif
  1280. X                chars_in = read(istack->fd, inbuf + 2, BUFSIZE);
  1281. X        } while (chars_in == -1 && errno == EINTR); /* Suppose it was interrupted by a signal */
  1282. X
  1283. X        switch (chars_in) {
  1284. X        case 0:
  1285. X            return last = EOF;
  1286. X        case -1:
  1287. X            uerror("read");
  1288. X            rc_exit(1);
  1289. X            /* NOTREACHED */
  1290. X        default:
  1291. X            chars_out = 2;
  1292. X            if (dashvee)
  1293. X                writeall(2, inbuf + 2, chars_in);
  1294. X            history();
  1295. X        }
  1296. X    }
  1297. X    return last = inbuf[chars_out++];
  1298. X}
  1299. X
  1300. X/* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
  1301. X
  1302. Xvoid initinput() {
  1303. X    istack = itop = ealloc(istacksize = 256 * sizeof (Input));
  1304. X    istack->t = FD;
  1305. X    istack->fd = -1;
  1306. X    realugchar = ugalive;
  1307. X}
  1308. X
  1309. X/* push an input source onto the stack. set up a new input buffer, and set the right getchar() */
  1310. X
  1311. Xvoid pushinput(int /*enum inputtype*/ t,...) {
  1312. X    SIZE_T count, idiff;
  1313. X    char **a;
  1314. X    va_list ap;
  1315. X
  1316. X    va_start(ap, t);
  1317. X
  1318. X    istack->index = chars_out;
  1319. X    istack->read = chars_in;
  1320. X    istack->ibuf = inbuf;
  1321. X    istack->lineno = lineno;
  1322. X    istack++;
  1323. X
  1324. X    idiff = istack - itop;
  1325. X
  1326. X    if (idiff >= istacksize / sizeof (Input)) {
  1327. X        itop = erealloc(itop, istacksize *= 2);
  1328. X        istack = itop + idiff;
  1329. X    }
  1330. X
  1331. X    istack->t = t;
  1332. X    if (t == FD) {
  1333. X        istack->fd = va_arg(ap, int);
  1334. X        realgchar = fdgchar;
  1335. X        inbuf = ealloc(BUFSIZE + 2);
  1336. X    } else {
  1337. X        count = strarraylen(a = va_arg(ap, char **));
  1338. X        sprint((inbuf = ealloc(count + 3)) + 2, "%a", a);
  1339. X        realgchar = stringgchar;
  1340. X    }
  1341. X
  1342. X    va_end(ap);
  1343. X
  1344. X    realugchar = ugalive;
  1345. X    chars_out = 2;
  1346. X    chars_in = 0;
  1347. X    lineno = 1;
  1348. X}
  1349. X
  1350. X/* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */
  1351. X
  1352. Xvoid popinput() {
  1353. X    if (istack->t == FD)
  1354. X        close(istack->fd);
  1355. X    efree(inbuf);
  1356. X
  1357. X    --istack;
  1358. X
  1359. X    realgchar = (istack->t == STRING ? stringgchar : fdgchar);
  1360. X
  1361. X    if (istack->fd == -1) { /* top of input stack */
  1362. X        realgchar = dead;
  1363. X        realugchar = ugdead;
  1364. X    }
  1365. X
  1366. X    inbuf = istack->ibuf;
  1367. X    chars_out = istack->index;
  1368. X    chars_in = istack->read;
  1369. X    lineno = istack->lineno;
  1370. X}
  1371. X
  1372. X/* flush input characters upto newline. Used by scanerror() */
  1373. X
  1374. Xvoid flushu() {
  1375. X    int c;
  1376. X
  1377. X    if (last == '\n' || last == EOF)
  1378. X        return;
  1379. X
  1380. X    while ((c = gchar()) != '\n' && c != EOF)
  1381. X        ; /* skip to newline */
  1382. X
  1383. X    if (c == EOF)
  1384. X        ugchar(c);
  1385. X}
  1386. X
  1387. X/* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
  1388. X
  1389. XNode *doit(boolean execit) {
  1390. X    boolean eof;
  1391. X    jmp_buf j;
  1392. X    Estack e1, e2;
  1393. X
  1394. X    setjmp(j);
  1395. X    except(ERROR, j, &e1);
  1396. X
  1397. X    for (eof = FALSE; !eof;) {
  1398. X        except(ARENA, NULL, &e2);
  1399. X
  1400. X        if (dashell) {
  1401. X            char *fname[3];
  1402. X
  1403. X            fname[1] = concat(varlookup("home"),word("/.rcrc",NULL))->w;
  1404. X            fname[2] = NULL;
  1405. X            rcrc = TRUE;
  1406. X            dashell = FALSE;
  1407. X            b_dot(fname);
  1408. X        }
  1409. X
  1410. X        if (interactive) {
  1411. X            Node *f;
  1412. X            List *s;
  1413. X
  1414. X            if ((f = fnlookup("prompt")) != NULL)
  1415. X                walk(treecpy(f, nalloc), TRUE);
  1416. X
  1417. X            if ((s = varlookup("prompt")) != NULL) {
  1418. X#ifdef READLINE
  1419. X                prompt = s->w;
  1420. X#else
  1421. X                fprint(2,"%s",s->w);
  1422. X#endif
  1423. X                prompt2 = (s->n == NULL ? "" : s->n->w);
  1424. X            }
  1425. X        }
  1426. X
  1427. X        inityy();
  1428. X
  1429. X        if (yyparse() < 0)
  1430. X            rc_raise(ERROR);
  1431. X
  1432. X        eof = (last == EOF); /* "last" can be clobbered during a walk() */
  1433. X
  1434. X        if (execit && parsetree != NULL)
  1435. X                walk(parsetree, TRUE);
  1436. X
  1437. X        unexcept(); /* ARENA */
  1438. X    }
  1439. X
  1440. X    popinput();
  1441. X    unexcept(); /* ERROR */
  1442. X    return parsetree;
  1443. X}
  1444. X
  1445. X/* parse a function imported from the environment */
  1446. X
  1447. XNode *parseline(char *extdef) {
  1448. X    char *in[2];
  1449. X    int i = interactive;
  1450. X    Node *ret;
  1451. X
  1452. X    in[0] = extdef;
  1453. X    in[1] = NULL;
  1454. X    interactive = FALSE;
  1455. X    pushinput(STRING, in);
  1456. X    ret = doit(FALSE);
  1457. X    interactive = i;
  1458. X    return ret;
  1459. X}
  1460. X
  1461. X/* write last command out to a file. Check to see if $history has changed, also */
  1462. X
  1463. Xstatic void history() {
  1464. X    List *histlist;
  1465. X    SIZE_T a;
  1466. X
  1467. X    if (!interactive)
  1468. X        return;
  1469. X
  1470. X    if ((histlist = varlookup("history")) == NULL) {
  1471. X        if (histstr != NULL) {
  1472. X            efree(histstr);
  1473. X            close(histfd);
  1474. X            histstr = NULL;
  1475. X        }
  1476. X        return;
  1477. X    }
  1478. X
  1479. X    if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */
  1480. X        if (histstr != NULL) {
  1481. X            efree(histstr);
  1482. X            close(histfd);
  1483. X        }
  1484. X        histstr = ecpy(histlist->w);
  1485. X        histfd = rc_open(histstr, APPEND);
  1486. X        if (histfd < 0) {
  1487. X            uerror(histstr);
  1488. X            efree(histstr);
  1489. X            histstr = NULL;
  1490. X        }
  1491. X    }
  1492. X
  1493. X    /*
  1494. X       small unix hack: since read() reads only up to a newline from a terminal, then
  1495. X       presumably this write() will write at most only one input line at a time.
  1496. X    */
  1497. X
  1498. X    for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */
  1499. X        if (inbuf[a] == '#' || inbuf[a] == '\n')
  1500. X            return;
  1501. X        if (inbuf[a] != ' ' && inbuf[a] != '\t')
  1502. X            break;
  1503. X    }
  1504. X    writeall(histfd, inbuf + 2, chars_in);
  1505. X}
  1506. END_OF_FILE
  1507.   if test 6937 -ne `wc -c <'input.c'`; then
  1508.     echo shar: \"'input.c'\" unpacked with wrong size!
  1509.   fi
  1510.   # end of 'input.c'
  1511. fi
  1512. if test -f 'lex.c' -a "${1}" != "-c" ; then 
  1513.   echo shar: Will not clobber existing file \"'lex.c'\"
  1514. else
  1515.   echo shar: Extracting \"'lex.c'\" \(10083 characters\)
  1516.   sed "s/^X//" >'lex.c' <<'END_OF_FILE'
  1517. X/* lex.c: rc's lexical analyzer */
  1518. X
  1519. X#include "rc.h"
  1520. X#include "lex.h"
  1521. X#include "y.tab.h"
  1522. X#include "nalloc.h"
  1523. X#include "input.h"
  1524. X#include "utils.h"
  1525. X#include "hash.h"
  1526. X#include "heredoc.h"
  1527. X
  1528. X/*
  1529. X    Special characters (i.e., "non-word") in rc:
  1530. X        \t \n # ; & | ^ $ = ~ ` ' { } @ ! ( ) < > \
  1531. X
  1532. X    The lexical analyzer is fairly straightforward. The only really unclean part
  1533. X    concerns backslash continuation and "double backslashes". A backslash followed by
  1534. X    a newline is treated as a space, otherwise backslash is not a special characeter
  1535. X    (i.e., it can be part of a word).  This introduces a host of unwanted special
  1536. X    cases. In our case, \ cannot be a word character, since we wish to read in all
  1537. X    word characters in a tight loop.
  1538. X
  1539. X    Note: to save the trouble of declaring these arrays with TRUEs and FALSEs, I am assuming
  1540. X    that FALSE = 0, TRUE = 1. (and so is it declared in rc.h)
  1541. X*/
  1542. X
  1543. X#define BUFSIZE ((SIZE_T) 1000)    /*    malloc hates power of 2 buffers? */
  1544. X#define BUFMAX (8 * BUFSIZE)    /*     How big the buffer can get before we re-allocate the
  1545. X                    space at BUFSIZE again. Premature optimization? Maybe.
  1546. X                */
  1547. X
  1548. Xenum wordstates { NW, RW, KW }; /* "nonword", "realword", "keyword" */
  1549. X
  1550. Xstatic void getpair(int);
  1551. X
  1552. Xint lineno;
  1553. X
  1554. Xconst char nw[] = {
  1555. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1556. X    1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
  1557. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
  1558. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
  1559. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1560. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1561. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1562. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  1563. X};
  1564. X
  1565. Xconst char dnw[] = {
  1566. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1567. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
  1568. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
  1569. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
  1570. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1571. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1572. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1573. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  1574. X};
  1575. X
  1576. Xstatic SIZE_T bufsize = BUFSIZE;
  1577. Xstatic char *realbuf = NULL;
  1578. Xstatic boolean newline = FALSE;
  1579. Xstatic enum wordstates word = NW;
  1580. Xstatic int fd_left, fd_right;
  1581. X
  1582. X#define checkfreecaret {if (*wp != NW) { *wp = NW; ugchar(c); return '^'; }}
  1583. X
  1584. Xenum filedescriptors { UNSET = -9, CLOSED = -1 };
  1585. X
  1586. Xint yylex() {
  1587. X    static boolean dollar = FALSE;
  1588. X    boolean saw_meta = FALSE;
  1589. X    int c;
  1590. X    SIZE_T i;            /* The purpose of all these local assignments is to    */
  1591. X    const char *meta;        /* allow optimizing compilers like gcc to load these    */
  1592. X    char *buf = realbuf;        /* values into registers. On a sparc this is a big    */
  1593. X    YYSTYPE *y = &yylval;        /* win, in code size *and* execution time        */
  1594. X    enum wordstates *wp = &word;
  1595. X
  1596. X    /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
  1597. X    meta = (dollar ? dnw : nw);
  1598. X    dollar = FALSE;
  1599. X
  1600. X    if (newline) {
  1601. X        --lineno; /* slight space optimization; print_prompt2() always increments lineno */
  1602. X        print_prompt2();
  1603. X        newline = FALSE;
  1604. X    }
  1605. X
  1606. Xtop:    while ((c = gchar()) == ' ' || c == '\t')
  1607. X        *wp = NW;
  1608. X
  1609. X    if (c == EOF)
  1610. X        return END;
  1611. X
  1612. X    if (!meta[c]) {    /* it's a word or keyword. */
  1613. X        checkfreecaret;
  1614. X        *wp = RW;
  1615. X        i = 0;
  1616. X    read:    do {
  1617. X            buf[i++] = c;
  1618. X            if (c == '?' || c == '[' || c == '*')
  1619. X                saw_meta = TRUE;
  1620. X            if (i >= bufsize)
  1621. X                buf = realbuf = erealloc(buf, bufsize *= 2);
  1622. X        } while ((c = gchar()) != EOF && !meta[c]);
  1623. X        if (c == '\\') {
  1624. X            if ((c = gchar()) == '\n') {
  1625. X                print_prompt2();
  1626. X                c = ' '; /* Pretend a space was read */
  1627. X            } else {
  1628. X    bs:            buf[i++] = '\\';
  1629. X                if (!meta[c] || c == '\\')
  1630. X                    goto read;
  1631. X            }
  1632. X        }
  1633. X        ugchar(c);
  1634. X        buf[i] = '\0';
  1635. X        *wp = KW;
  1636. X        if (i == 2) {
  1637. X            if (*buf == 'i' && buf[1] == 'f') return IF;
  1638. X            if (*buf == 'f' && buf[1] == 'n') return FN;
  1639. X            if (*buf == 'i' && buf[1] == 'n') return IN;
  1640. X        }
  1641. X        if (streq(buf,"for")) return FOR;
  1642. X        if (streq(buf,"else")) return ELSE;
  1643. X        if (streq(buf,"switch")) return SWITCH;
  1644. X        if (streq(buf,"while")) return WHILE;
  1645. X        *wp = RW;
  1646. X        y->word.w = ncpy(buf);
  1647. X        if (saw_meta) {
  1648. X            char *r, *s;
  1649. X
  1650. X            y->word.m = nalloc(strlen(buf) + 1);
  1651. X            for (r = buf, s = y->word.m; *r != '\0'; r++, s++)
  1652. X                *s = (*r == '?' || *r == '[' || *r == '*');
  1653. X        } else {
  1654. X            y->word.m = NULL;
  1655. X        }
  1656. X        return WORD;
  1657. X    }
  1658. X
  1659. X    if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
  1660. X        checkfreecaret;
  1661. X        if (c == '!' || c == '@' || c == '~')
  1662. X            *wp = KW;
  1663. X    }
  1664. X
  1665. X    switch (c) {
  1666. X    case '\0':
  1667. X        scanerror("null character");
  1668. X        /* NOTREACHED */
  1669. X    case '!':
  1670. X        return BANG;
  1671. X    case '@':
  1672. X        return SUBSHELL;
  1673. X    case '~':
  1674. X        return TWIDDLE;
  1675. X    case '`':
  1676. X        c = gchar();
  1677. X        if (c == '`')
  1678. X            return BACKBACK;
  1679. X        ugchar(c);
  1680. X        return '`';
  1681. X    case '$':
  1682. X        dollar = TRUE;
  1683. X        c = gchar();
  1684. X        if (c == '#')
  1685. X            return COUNT;
  1686. X        if (c == '^')
  1687. X            return FLAT;
  1688. X        ugchar(c);
  1689. X        return '$';
  1690. X    case '\'':
  1691. X        *wp = RW;
  1692. X        i = 0;
  1693. X        do {
  1694. X            buf[i++] = c;
  1695. X            if (c == '\n')
  1696. X                print_prompt2();
  1697. X            if (c == EOF)
  1698. X                scanerror("eof in quoted string");
  1699. X            if (i >= bufsize)
  1700. X                buf = realbuf = erealloc(buf, bufsize *= 2);
  1701. X        } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */
  1702. X        ugchar(c);
  1703. X        buf[i] = '\0';
  1704. X        y->word.w = ncpy(buf);
  1705. X        y->word.m = NULL;
  1706. X        return WORD;
  1707. X    case '\\':
  1708. X        if ((c = gchar()) == '\n') {
  1709. X            print_prompt2();
  1710. X            goto top; /* Pretend it was just another space. */
  1711. X        }
  1712. X        ugchar(c);
  1713. X        c = '\\';
  1714. X        checkfreecaret;
  1715. X        c = gchar();
  1716. X        i = 0;
  1717. X        goto bs;
  1718. X    case '(':
  1719. X        if (*wp == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */
  1720. X            c = SUB;
  1721. X        *wp = NW;
  1722. X        return c;
  1723. X    case '#':
  1724. X        while ((c = gchar()) != '\n') /* skip comment until newline */
  1725. X            if (c == EOF)
  1726. X                return END;
  1727. X        /* FALLTHROUGH */
  1728. X    case '\n':
  1729. X        lineno++;
  1730. X        newline = TRUE;
  1731. X        /* FALLTHROUGH */
  1732. X    case ';':
  1733. X    case '^':
  1734. X    case ')':
  1735. X    case '=':
  1736. X    case '{': case '}':
  1737. X        *wp = NW;
  1738. X        return c;
  1739. X    case '&':
  1740. X        *wp = NW;
  1741. X        c = gchar();
  1742. X        if (c == '&')
  1743. X            return ANDAND;
  1744. X        ugchar(c);
  1745. X        return '&';
  1746. X    case '|':
  1747. X        *wp = NW;
  1748. X        c = gchar();
  1749. X        if (c == '|')
  1750. X            return OROR;
  1751. X        getpair(c);
  1752. X        if ((y->pipe.left = fd_left) == UNSET)
  1753. X            y->pipe.left = 1;                /* default to fd 1 */
  1754. X        if ((y->pipe.right = fd_right) == UNSET)
  1755. X            y->pipe.right = 0;                /* default to fd 0 */
  1756. X        if (y->pipe.right == CLOSED)
  1757. X            scanerror("expected digit after '='");        /* can't close a pipe */
  1758. X        return PIPE;
  1759. X    case '>':
  1760. X        c = gchar();
  1761. X        if (c == '>') {
  1762. X            c = gchar();
  1763. X            y->redir.type = APPEND;
  1764. X        } else
  1765. X            y->redir.type = CREATE;
  1766. X        y->redir.fd = 1;
  1767. X        goto common;
  1768. X    case '<':
  1769. X        c = gchar();
  1770. X        if (c == '<') {
  1771. X            c = gchar();
  1772. X            if (c == '<') {
  1773. X                c = gchar();
  1774. X                y->redir.type = HERESTRING;
  1775. X            } else {
  1776. X                y->redir.type = HEREDOC;
  1777. X            }
  1778. X        } else
  1779. X            y->redir.type = FROM;
  1780. X        y->redir.fd = 0;
  1781. X    common:
  1782. X        *wp = NW;
  1783. X        getpair(c);
  1784. X        if (fd_right == UNSET) { /* redirection, not dup */
  1785. X            if (fd_left != UNSET)
  1786. X                y->redir.fd = fd_left;
  1787. X            return REDIR;
  1788. X        } else { /* dup; recast yylval */
  1789. X            y->dup.type = y->redir.type;
  1790. X            y->dup.left = fd_left;
  1791. X            y->dup.right = fd_right;
  1792. X            return DUP;
  1793. X        }
  1794. X    default:
  1795. X        *wp = NW;
  1796. X        return c; /* don't know what it is, let yacc barf on it */
  1797. X    }
  1798. X}
  1799. X
  1800. Xvoid skipnl(void) {
  1801. X    int c;
  1802. X
  1803. X    while ((c = gchar()) == ' ' || c == '\t' || c == '#' || c == '\n') {
  1804. X        if (c == '\n' || c == '#') {
  1805. X            for (; c != '\n'; c = gchar()) /* skip comments */
  1806. X                if (c == EOF) {
  1807. X                    ugchar(c);
  1808. X                    return;
  1809. X                }
  1810. X            print_prompt2();
  1811. X        }
  1812. X    }
  1813. X    ugchar(c);
  1814. X}
  1815. X
  1816. Xvoid yyerror(const char *s) {
  1817. X    char *tok;
  1818. X    char tokbuf[128];
  1819. X
  1820. X    if (!interactive) {
  1821. X        if (word != NW)
  1822. X            tok = realbuf;
  1823. X        else if (last == EOF)
  1824. X            tok = "end of input";
  1825. X        else if (last == '\n')
  1826. X            tok = "end of line";
  1827. X        else
  1828. X            sprint(tok = tokbuf, (last < 32 || last > 126) ? "(decimal %d)" : "'%c'",last);
  1829. X        fprint(2,"line %d: %s near %s\n", lineno - (last == '\n'), s, tok);
  1830. X    } else
  1831. X        fprint(2,"%s\n",s);
  1832. X}
  1833. X
  1834. Xvoid scanerror(char *s) {
  1835. X    flushu(); /* flush upto newline */
  1836. X    rc_error(s);
  1837. X}
  1838. X
  1839. Xvoid inityy(void) {
  1840. X    newline = FALSE;
  1841. X    word = NW;
  1842. X    hq = NULL;
  1843. X
  1844. X    /* return memory to the system if the buffer got too large */
  1845. X
  1846. X    if (bufsize > BUFMAX && realbuf != NULL) {
  1847. X        efree(realbuf);
  1848. X        bufsize = BUFSIZE;
  1849. X        realbuf = ealloc(bufsize);
  1850. X    } else if (realbuf == NULL)
  1851. X        realbuf = ealloc(bufsize);
  1852. X}
  1853. X
  1854. Xvoid print_prompt2() {
  1855. X    lineno++;
  1856. X#ifdef READLINE
  1857. X    prompt = prompt2;
  1858. X#else
  1859. X    if (interactive)
  1860. X        fprint(2,"%s",prompt2);
  1861. X#endif
  1862. X}
  1863. X
  1864. X/*
  1865. X   Scan in a pair of integers for redirections like >[2=1]. CLOSED represents a closed file
  1866. X   descriptor (i.e., >[2=]) and UNSET represents an undesignated file descriptor (e.g.,
  1867. X   >[2] is represented as (2,UNSET).
  1868. X
  1869. X   This function makes use of unsigned compares to make range tests in one compare operation.
  1870. X*/
  1871. X
  1872. Xstatic void getpair(int c) {
  1873. X    int n;
  1874. X
  1875. X    fd_left = fd_right = UNSET;
  1876. X
  1877. X    if (c != '[') {
  1878. X        ugchar(c);
  1879. X        return;
  1880. X    }
  1881. X
  1882. X    if ((unsigned int) (n = gchar() - '0') > 9)
  1883. X        scanerror("expected digit after '['");
  1884. X
  1885. X    while ((unsigned int) (c = gchar() - '0') <= 9)
  1886. X        n = n * 10 + c;
  1887. X
  1888. X    fd_left = n;
  1889. X    c += '0';
  1890. X
  1891. X    switch (c) {
  1892. X    default:
  1893. X        scanerror("expected '=' or ']' after digit");
  1894. X        /* NOTREACHED */
  1895. X    case ']':
  1896. X        return;
  1897. X    case '=':
  1898. X        if ((unsigned int) (n = gchar() - '0') > 9) {
  1899. X            if (n != ']' - '0')
  1900. X                scanerror("expected digit or ']' after '='");
  1901. X            fd_right = CLOSED;
  1902. X        } else {
  1903. X            while ((unsigned int) (c = gchar() - '0') <= 9)
  1904. X                n = n * 10 + c;
  1905. X            if (c != ']' - '0')
  1906. X                scanerror("expected ']' after digit");
  1907. X            fd_right = n;
  1908. X        }
  1909. X    }
  1910. X}
  1911. END_OF_FILE
  1912.   if test 10083 -ne `wc -c <'lex.c'`; then
  1913.     echo shar: \"'lex.c'\" unpacked with wrong size!
  1914.   fi
  1915.   # end of 'lex.c'
  1916. fi
  1917. if test -f 'walk.c' -a "${1}" != "-c" ; then 
  1918.   echo shar: Will not clobber existing file \"'walk.c'\"
  1919. else
  1920.   echo shar: Extracting \"'walk.c'\" \(8357 characters\)
  1921.   sed "s/^X//" >'walk.c' <<'END_OF_FILE'
  1922. X/* walk.c: walks the parse tree. */
  1923. X
  1924. X#include <setjmp.h>
  1925. X#include <signal.h>
  1926. X#include "rc.h"
  1927. X#include "utils.h"
  1928. X#include "status.h"
  1929. X#include "exec.h"
  1930. X#include "walk.h"
  1931. X#include "glom.h"
  1932. X#include "hash.h"
  1933. X#include "glob.h"
  1934. X#include "lex.h"
  1935. X#include "open.h"
  1936. X#include "except.h"
  1937. X
  1938. Xboolean cond = FALSE;
  1939. X
  1940. Xstatic boolean iscase(Node *);
  1941. Xstatic boolean isallpre(Node *);
  1942. Xstatic boolean dofork(void);
  1943. X
  1944. X/* walk the parse-tree. "obvious". */
  1945. X
  1946. Xboolean walk(Node *n, boolean parent) {
  1947. X    if (n == NULL) {
  1948. X        if (!parent)
  1949. X            exit(0);
  1950. X        set(TRUE);
  1951. X        return TRUE;
  1952. X    }
  1953. X
  1954. X    switch (n->type) {
  1955. X    case ARGS: case BACKQ: case CONCAT: case rCOUNT: case rFLAT:
  1956. X    case LAPPEND: case rREDIR: case VAR: case VARSUB: case rWORD:
  1957. X        exec(glob(glom(n)), parent);    /* simple command */
  1958. X        break;
  1959. X    case BODY:
  1960. X        walk(n->u[0].p, TRUE);
  1961. X        walk(n->u[1].p, TRUE);
  1962. X        break;
  1963. X    case NOWAIT: {
  1964. X        int pid;
  1965. X        char apid[8];
  1966. X
  1967. X        switch (pid = fork()) {
  1968. X        case -1:
  1969. X            uerror("fork");
  1970. X            rc_error(NULL);
  1971. X            /* NOTREACHED */
  1972. X        case 0:
  1973. X            setsigdefaults();
  1974. X#ifdef NOJOB
  1975. X            signal(SIGINT, SIG_IGN);    /* traditional backgrounding procedure: ignore SIGINT */
  1976. X#else
  1977. X            signal(SIGTTOU, SIG_IGN);    /* Berkeleyized version: put it in a new pgroup. */
  1978. X            signal(SIGTTIN, SIG_IGN);
  1979. X            signal(SIGTSTP, SIG_IGN);
  1980. X            setpgrp(0, getpid());
  1981. X#endif
  1982. X            dup2(rc_open("/dev/null", FROM), 0);
  1983. X            walk(n->u[0].p, FALSE);
  1984. X            exit(getstatus());
  1985. X            /* NOTREACHED */
  1986. X        default:
  1987. X            if (interactive)
  1988. X                fprint(2,"%d\n",pid);
  1989. X            varassign("apid", word(sprint(apid,"%d",pid), NULL), FALSE);
  1990. X            redirq = NULL; /* kill pre-redir queue */
  1991. X            fifoq = NULL;
  1992. X        }
  1993. X        break;
  1994. X    }
  1995. X    case rANDAND: {
  1996. X        boolean oldcond = cond;
  1997. X
  1998. X        cond = TRUE;
  1999. X        if (walk(n->u[0].p, TRUE)) {
  2000. X            cond = oldcond;
  2001. X            walk(n->u[1].p, TRUE);
  2002. X        } else
  2003. X            cond = oldcond;
  2004. X        break;
  2005. X    }
  2006. X    case rOROR: {
  2007. X        boolean oldcond = cond;
  2008. X
  2009. X        cond = TRUE;
  2010. X        if (!walk(n->u[0].p, TRUE)) {
  2011. X            cond = oldcond;
  2012. X            walk(n->u[1].p, TRUE);
  2013. X        } else
  2014. X            cond = oldcond;
  2015. X        break;
  2016. X    }
  2017. X    case rBANG:
  2018. X        set(!walk(n->u[0].p, TRUE));
  2019. X        break;
  2020. X    case rIF: {
  2021. X        boolean oldcond = cond;
  2022. X        Node *true_cmd = n->u[1].p, *false_cmd = NULL;
  2023. X
  2024. X        if (true_cmd != NULL && true_cmd->type == rELSE) {
  2025. X            false_cmd = true_cmd->u[1].p;
  2026. X            true_cmd = true_cmd->u[0].p;
  2027. X        }
  2028. X        cond = TRUE;
  2029. X        if (!walk(n->u[0].p, TRUE))
  2030. X            true_cmd = false_cmd; /* run the else clause */
  2031. X        cond = oldcond;
  2032. X        walk(true_cmd, TRUE);
  2033. X        break;
  2034. X    }
  2035. X    case rWHILE: {
  2036. X        jmp_buf j;
  2037. X        boolean oldcond = cond;
  2038. X        Estack e1,e2;
  2039. X
  2040. X        cond = TRUE;
  2041. X
  2042. X        if (!walk(n->u[0].p, TRUE)) { /* prevent spurious breaks inside test */
  2043. X            cond = oldcond;
  2044. X            break;
  2045. X        }
  2046. X
  2047. X        if (setjmp(j))
  2048. X            break;
  2049. X
  2050. X        except(BREAK, j, &e1);
  2051. X        do {
  2052. X            cond = oldcond;
  2053. X            except(ARENA, NULL, &e2);
  2054. X            walk(n->u[1].p, TRUE);
  2055. X            unexcept(); /* ARENA */
  2056. X            cond = TRUE;
  2057. X        } while (walk(n->u[0].p, TRUE));
  2058. X        cond = oldcond;
  2059. X        unexcept(); /* BREAK */
  2060. X        break;
  2061. X    }
  2062. X    case FORIN: {
  2063. X        List *l;
  2064. X        jmp_buf j;
  2065. X        Estack e1,e2;
  2066. X
  2067. X        if (setjmp(j))
  2068. X            break;
  2069. X
  2070. X        except(BREAK, j, &e1);
  2071. X        for (l = glob(glom(n->u[1].p)); l != NULL; l = l->n) {
  2072. X            assign(glom(n->u[0].p), word(l->w, NULL), FALSE);
  2073. X            except(ARENA, NULL, &e2);
  2074. X            walk(n->u[2].p, TRUE);
  2075. X            unexcept(); /* ARENA */
  2076. X        }
  2077. X        unexcept(); /* BREAK */
  2078. X        break;
  2079. X    }
  2080. X    case rSUBSHELL:
  2081. X        if (dofork()) {
  2082. X            setsigdefaults();
  2083. X            walk(n->u[0].p, TRUE);
  2084. X            rc_exit(getstatus());
  2085. X        }
  2086. X        break;
  2087. X    case ASSIGN:
  2088. X        if (n->u[0].p == NULL)
  2089. X            rc_error("null variable name");
  2090. X        assign(glom(n->u[0].p), glob(glom(n->u[1].p)), FALSE);
  2091. X        set(TRUE);
  2092. X        break;
  2093. X    case rPIPE: {
  2094. X        int i, j, k, sp, pid, wpid, fd_prev, fd_out, pids[512], stats[512], p[2];
  2095. X        void (*handler)(int);
  2096. X        Node *r;
  2097. X
  2098. X        fd_prev = fd_out = 1;
  2099. X
  2100. X        for (r = n, i = 0; r != NULL && r->type == rPIPE; r = r->u[2].p, i++) {
  2101. X            if (i > 500)    /* the only hard-wired limit in rc? */
  2102. X                rc_error("pipe too long");
  2103. X
  2104. X            if (pipe(p) < 0) {
  2105. X                uerror("pipe");
  2106. X                rc_error(NULL);
  2107. X            }
  2108. X
  2109. X            switch (pid = fork()) {
  2110. X            case -1:
  2111. X                uerror("fork");
  2112. X                rc_error(NULL);
  2113. X                /* NOTREACHED */
  2114. X            case 0:
  2115. X                setsigdefaults();
  2116. X                redirq = NULL; /* clear preredir queue */
  2117. X                fifoq = NULL;
  2118. X                dup2(p[0],r->u[1].i);
  2119. X                if (fd_prev != 1) {
  2120. X                    dup2(fd_prev, fd_out);
  2121. X                    close(fd_prev);
  2122. X                }
  2123. X                close(p[0]);
  2124. X                close(p[1]);
  2125. X                walk(r->u[3].p, FALSE);
  2126. X                exit(getstatus());
  2127. X                /* NOTREACHED */
  2128. X            default:
  2129. X                if (fd_prev != 1)
  2130. X                    close(fd_prev); /* parent must close all pipe fd's */
  2131. X                pids[i] = pid;
  2132. X                fd_prev = p[1];
  2133. X                fd_out = r->u[0].i;
  2134. X                close(p[0]);
  2135. X            }
  2136. X        }
  2137. X
  2138. X        switch (pid = fork()) {
  2139. X        case -1:
  2140. X            uerror("fork");
  2141. X            rc_error(NULL);
  2142. X            /* NOTREACHED */
  2143. X        case 0:
  2144. X            setsigdefaults();
  2145. X            dup2(fd_prev, fd_out);
  2146. X            close(fd_prev);
  2147. X            walk(r, FALSE);
  2148. X            exit(getstatus());
  2149. X            /* NOTREACHED */
  2150. X        default:
  2151. X            redirq = NULL; /* clear preredir queue */
  2152. X            fifoq = NULL;
  2153. X            close(fd_prev);
  2154. X            pids[i++] = pid;
  2155. X
  2156. X            /* collect statuses */
  2157. X
  2158. X            if ((handler = signal(SIGINT, SIG_IGN)) == SIG_DFL)
  2159. X                signal(SIGINT, SIG_DFL); /* don't ignore interrupts in noninteractive mode */
  2160. X
  2161. X            for (k = i; k != 0;) {
  2162. X                if ((wpid = wait(&sp)) < 0)
  2163. X                    uerror("wait");
  2164. X                for (j = 0; j < i; j++)
  2165. X                    if (wpid == pids[j]) {
  2166. X                        stats[j] = sp;
  2167. X                        pids[j] = 0;
  2168. X                        --k;
  2169. X                    }
  2170. X            }
  2171. X
  2172. X            setpipestatus(stats, i);
  2173. X            signal(SIGINT, handler);
  2174. X        }
  2175. X        break;
  2176. X    }
  2177. X    case NEWFN: {
  2178. X        List *l = glom(n->u[0].p);
  2179. X
  2180. X        if (l == NULL)
  2181. X            rc_error("null function name");
  2182. X        while (l != NULL) {
  2183. X            fnassign(l->w, n->u[1].p);
  2184. X            l = l->n;
  2185. X        }
  2186. X        set(TRUE);
  2187. X        break;
  2188. X    }
  2189. X    case RMFN: {
  2190. X        List *l = glom(n->u[0].p);
  2191. X
  2192. X        while (l != NULL) {
  2193. X            fnrm(l->w);
  2194. X            l = l->n;
  2195. X        }
  2196. X        set(TRUE);
  2197. X        break;
  2198. X    }
  2199. X    case rDUP:
  2200. X        break; /* Null command */
  2201. X    case MATCH:
  2202. X        set(lmatch(glob(glom(n->u[0].p)), glom(n->u[1].p)));
  2203. X        break;
  2204. X    case rSWITCH: {
  2205. X        List *v = glom(n->u[0].p);
  2206. X
  2207. X        while (1) {
  2208. X            do {
  2209. X                n = n->u[1].p;
  2210. X                if (n == NULL || n->type != BODY)
  2211. X                    return istrue();
  2212. X            } while (!iscase(n->u[0].p));
  2213. X            if (lmatch(v, glom(n->u[0].p)->n)) {
  2214. X                for (n = n->u[1].p; n != NULL && !iscase(n->u[0].p); n = n->u[1].p) {
  2215. X                    if (n->type != BODY) { /* special case at the end of BODY subtree */
  2216. X                        walk(n, TRUE);
  2217. X                        break;
  2218. X                    }
  2219. X                    walk(n->u[0].p, TRUE);
  2220. X                }
  2221. X                break;
  2222. X            }
  2223. X        }
  2224. X        break;
  2225. X    }
  2226. X    case PRE: {
  2227. X        List *v;
  2228. X
  2229. X        if (n->u[0].p->type == rREDIR) {
  2230. X            qredir(n->u[0].p);
  2231. X            walk(n->u[1].p, TRUE);
  2232. X            break;
  2233. X        } else if (n->u[0].p->type == ASSIGN) {
  2234. X            if (isallpre(n->u[1].p)) {
  2235. X                walk(n->u[0].p, TRUE);
  2236. X                walk(n->u[1].p, TRUE);
  2237. X                break;
  2238. X            } else {
  2239. X                v = glom(n->u[0].p->u[0].p);
  2240. X                assign(v, glob(glom(n->u[0].p->u[1].p)), TRUE);
  2241. X                walk(n->u[1].p, TRUE);
  2242. X                varrm(v->w, TRUE);
  2243. X            }
  2244. X        } else
  2245. X            rc_error("walk: node other than assign or redir in PRE. help!");
  2246. X        break;
  2247. X    }
  2248. X    case BRACE:
  2249. X        if (dofork()) {
  2250. X            setsigdefaults();
  2251. X            walk(n->u[1].p, TRUE); /* Do redirections */
  2252. X            redirq = NULL;   /* Reset redirection queue */
  2253. X            walk(n->u[0].p, TRUE); /* Do commands */
  2254. X            rc_exit(getstatus());
  2255. X            /* NOTREACHED */
  2256. X        }
  2257. X        break;
  2258. X    case EPILOG:
  2259. X        qredir(n->u[0].p);
  2260. X        if (n->u[1].p != NULL)
  2261. X            walk(n->u[1].p, TRUE); /* Do more redirections. */
  2262. X        else
  2263. X            doredirs();    /* Okay, we hit the bottom. */
  2264. X        break;
  2265. X    case NMPIPE:
  2266. X        rc_error("named pipes cannot be executed as commands");
  2267. X        /* NOTREACHED */
  2268. X    default:
  2269. X        rc_error("walk: unknown node; this can't happen");
  2270. X        /* NOTREACHED */
  2271. X    }
  2272. X    return istrue();
  2273. X}
  2274. X
  2275. X/* checks a "command-line" (in parsetree form) to see if it contains the fake keyword "case". */
  2276. X
  2277. Xstatic boolean iscase(Node *n) {
  2278. X    if (n == NULL)
  2279. X        return FALSE;
  2280. X
  2281. X    switch (n->type) {
  2282. X    case rWORD:
  2283. X        return streq(n->u[0].s, "case");
  2284. X    case ARGS: case LAPPEND:
  2285. X        return iscase(n->u[0].p);
  2286. X    default:
  2287. X        return FALSE;
  2288. X    }
  2289. X}
  2290. X
  2291. X/* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
  2292. X
  2293. Xstatic boolean isallpre(Node *n) {
  2294. X    if (n == NULL)
  2295. X        return TRUE;
  2296. X
  2297. X    switch (n->type) {
  2298. X    case PRE:
  2299. X        return isallpre(n->u[1].p);
  2300. X    case rREDIR: case ASSIGN: case rDUP:
  2301. X        return TRUE;
  2302. X    default:
  2303. X        return FALSE;
  2304. X    }
  2305. X}
  2306. X
  2307. X/*
  2308. X   A code-saver. Forks, child returns (for further processing in walk()), and the parent
  2309. X   waits for the child to finish, setting $status appropriately.
  2310. X*/
  2311. X
  2312. Xstatic boolean dofork() {
  2313. X    int pid, sp;
  2314. X
  2315. X    switch (pid = fork()) {
  2316. X    case -1:
  2317. X        uerror("fork");
  2318. X        rc_error(NULL);
  2319. X        /* NOTREACHED */
  2320. X    case 0:
  2321. X        return TRUE;
  2322. X    default:
  2323. X        redirq = NULL; /* clear out the pre-redirection queue in the parent */
  2324. X        fifoq = NULL;
  2325. X        while (pid != wait(&sp))
  2326. X            if (pid < 0)
  2327. X                uerror("wait");
  2328. X        setstatus(sp);
  2329. X        return FALSE;
  2330. X    }
  2331. X}
  2332. X
  2333. END_OF_FILE
  2334.   if test 8357 -ne `wc -c <'walk.c'`; then
  2335.     echo shar: \"'walk.c'\" unpacked with wrong size!
  2336.   fi
  2337.   # end of 'walk.c'
  2338. fi
  2339. echo shar: End of archive 2 \(of 4\).
  2340. cp /dev/null ark2isdone
  2341. MISSING=""
  2342. for I in 1 2 3 4 ; do
  2343.     if test ! -f ark${I}isdone ; then
  2344.     MISSING="${MISSING} ${I}"
  2345.     fi
  2346. done
  2347. if test "${MISSING}" = "" ; then
  2348.     echo You have unpacked all 4 archives.
  2349.     rm -f ark[1-9]isdone
  2350. else
  2351.     echo You still must unpack the following archives:
  2352.     echo "        " ${MISSING}
  2353. fi
  2354. exit 0
  2355. exit 0 # Just in case...
  2356. -- 
  2357. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2358. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2359. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2360. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2361.